package cc.rengu.igas.bomp.core.service.trans;

import cc.rengu.igas.bomp.common.constant.BompAppParamConstant;
import cc.rengu.igas.bomp.common.constant.DubboMethodConstant;
import cc.rengu.igas.bomp.common.enums.RespCodeEnum;
import cc.rengu.igas.bomp.common.enums.SettleAcctTypeEnum;
import cc.rengu.igas.bomp.core.service.base.ManageService;
import cc.rengu.igas.bomp.facade.request.AcctRealNameAuthRequest;
import cc.rengu.igas.bomp.facade.response.AcctRealNameAuthResponse;
import cc.rengu.igas.share.common.util.GlobalEsbUtil;
import cc.rengu.igas.smps.facade.BankSupService;
import cc.rengu.igas.smps.facade.base.Header;
import cc.rengu.igas.smps.facade.request.BankAcctInfoQueryRequest;
import cc.rengu.igas.smps.facade.request.BankFourElementVerifyRequest;
import cc.rengu.igas.smps.facade.response.BankAcctInfoQueryResponse;
import cc.rengu.igas.smps.facade.response.BankFourElementVerifyResponse;
import cc.rengu.igas.smps.facade.result.Result;
import cc.rengu.oltp.service.common.constant.AppParamConstant;
import cc.rengu.oltp.service.common.constant.TreeNodeConstant;
import cc.rengu.oltp.service.common.entity.BinInfo;
import cc.rengu.oltp.service.common.entity.ChannelCallCfg;
import cc.rengu.oltp.service.common.entity.SysParam;
import cc.rengu.oltp.service.common.enums.ChannelEnum;
import cc.rengu.oltp.service.model.BizException;
import cc.rengu.oltp.service.model.BizResponse;
import cc.rengu.oltp.service.realize.BinInfoService;
import cc.rengu.oltp.service.realize.DubboService;
import cc.rengu.oltp.service.realize.SysParamService;
import cc.rengu.oltp.service.realize.impl.BinInfoServiceImpl;
import cc.rengu.oltp.service.realize.impl.DubboServiceImpl;
import cc.rengu.oltp.service.realize.impl.SysParamServiceImpl;
import cc.rengu.oltp.utility.util.*;

/**
 * 账户实名认证服务
 * Created by 王成 on 2018/7/3.
 *
 * @author zhangxr
 * @version 1.0
 * @date 2020.04.21
 * 业务处理流程：
 * 1、判断是否为本行卡，若为他行卡则返回失败，结束流程
 * 2、调用ESB接口获取账户信息，组装数据返回
 */
public class AcctRealNameAuthService extends ManageService {

    @Override
    protected Object bizBeforeCust() throws Exception {
        AcctRealNameAuthRequest acctRealNameAuthRequest = new AcctRealNameAuthRequest();
        ConvertUtil.convertOutput(acctRealNameAuthRequest);
        if (StringUtil.isEmptyOrNull(acctRealNameAuthRequest.getAcctNo())
                || StringUtil.isEmptyOrNull(acctRealNameAuthRequest.getAcctName())
                || StringUtil.isEmptyOrNull(acctRealNameAuthRequest.getSettleAcctType())) {
            rglog.error("账户实名认证服务处理失败，必填项参数为空！");
            throw new BizException(RespCodeEnum.MSG_VALID_CHECK_ERROR.getRespCode(), RespCodeEnum.MSG_VALID_CHECK_ERROR.getRespDesc());
        }

        return acctRealNameAuthRequest;
    }

    @Override
    protected BizResponse bizProcessCust(Object request) throws Exception {
        AcctRealNameAuthRequest acctRealNameAuthRequest = (AcctRealNameAuthRequest) request;
        AcctRealNameAuthResponse acctRealNameAuthResponse = new AcctRealNameAuthResponse();
        acctRealNameAuthResponse.setHeader(acctRealNameAuthRequest.getHeader());
        BizResponse<AcctRealNameAuthResponse> bizResponse = new BizResponse<>();

        String instId = acctRealNameAuthRequest.getHeader().getInstId();
        XmlTreeUtil xmlTreeUtil = new XmlTreeUtil();
        String sysSeqNum = xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.SYS_SEQ_NUM);

        /* step1: 校验是否为本行卡 */
        if (SettleAcctTypeEnum.SELF_DEBIT.getAcctType().equals(acctRealNameAuthRequest.getSettleAcctType())
                || SettleAcctTypeEnum.SELF_CREDIT.getAcctType().equals(acctRealNameAuthRequest.getSettleAcctType())
                || SettleAcctTypeEnum.SELFT_PASSBOOK.getAcctType().equals(acctRealNameAuthRequest.getSettleAcctType())
                || SettleAcctTypeEnum.SELF_INTERNAL.getAcctType().equals(acctRealNameAuthRequest.getSettleAcctType())
                || SettleAcctTypeEnum.SELF_PUBLIC.getAcctType().equals(acctRealNameAuthRequest.getSettleAcctType())) {
            rglog.info("账户实名认证服，sysSeqNum:{}, 卡类型:{}", sysSeqNum, SettleAcctTypeEnum.getAcctDescByacctType(acctRealNameAuthRequest.getSettleAcctType()));
        } else {
            rglog.error("账户实名认证服务失败！只支持本行卡进行实名认证！sysSeqNum:{}, 卡类型:{}", sysSeqNum, acctRealNameAuthRequest.getSettleAcctType());
            throw new BizException(RespCodeEnum.NOT_SUPPORT_ORT_TYPE.getRespCode(), RespCodeEnum.NOT_SUPPORT_ORT_TYPE.getRespDesc());
        }

        /* todo 演示环境默认返回成功 */
        if (AppParamConstant.DEFAULT_ENV.equals(AppParamConstant.APPLICATION_ENV)) {
            acctRealNameAuthResponse.setAuthResult(BompAppParamConstant.FLAG_Y);
            acctRealNameAuthResponse.setRespCode(RespCodeEnum.TRANS_SUCCESS.getRespCode());
            acctRealNameAuthResponse.setRespDesc(RespCodeEnum.TRANS_SUCCESS.getRespDesc());
            acctRealNameAuthResponse.setAcctStatus("00");
            acctRealNameAuthResponse.setAcctType(acctRealNameAuthRequest.getSettleAcctType());
            bizResponse.setRspSysId(AppParamConstant.SYS_ID);
            bizResponse.setRespCode(acctRealNameAuthResponse.getRespCode());
            bizResponse.setRespDesc(acctRealNameAuthResponse.getRespDesc());
            bizResponse.setResult(acctRealNameAuthResponse);
            return bizResponse;
        }

        /* step2：获取本行账户信息 */
        Result<BankAcctInfoQueryResponse> result = invokeEsbToGetCoreAcctInfoQueryResponse(acctRealNameAuthRequest);
        if (null == result) {
            rglog.error("账户实名认证服务失败！调用ESB通道的账户信息查询coreAcctInfoQueryResponse返回失败");
            acctRealNameAuthResponse.setRespCode(RespCodeEnum.CALL_BIZ_SERVICE_ERROR.getRespCode());
            acctRealNameAuthResponse.setRespDesc(RespCodeEnum.CALL_BIZ_SERVICE_ERROR.getRespCode());
            acctRealNameAuthResponse.setAuthResult(BompAppParamConstant.FLAG_N);
            bizResponse.setRspSysId(AppParamConstant.SYS_ID);
            bizResponse.setRespCode(acctRealNameAuthResponse.getRespCode());
            bizResponse.setRespDesc(acctRealNameAuthResponse.getRespDesc());
            bizResponse.setResult(acctRealNameAuthResponse);
            return bizResponse;
        } else if (!result.isSuccess() || !DubboMethodConstant.DUBBO_SUCCESS.equals(result.getResult().getRespCode())) {
            rglog.error("账户实名认证服务失败！调用ESB通道的账户信息查询coreAcctInfoQueryResponse返回失败,errorCode:{},errorMsg:{}",
                    result.getResult().getRespCode(), result.getResult().getRespDesc());
            acctRealNameAuthResponse.setRespCode(result.getResult().getRespCode());
            acctRealNameAuthResponse.setRespDesc(result.getResult().getRespDesc());
            acctRealNameAuthResponse.setAuthResult(BompAppParamConstant.FLAG_N);
            bizResponse.setRspSysId(AppParamConstant.SYS_ID);
            bizResponse.setRespCode(acctRealNameAuthResponse.getRespCode());
            bizResponse.setRespDesc(acctRealNameAuthResponse.getRespDesc());
            bizResponse.setResult(acctRealNameAuthResponse);
            return bizResponse;
        }

        BankAcctInfoQueryResponse coreAcctInfoQueryResponse = result.getResult();
        acctRealNameAuthResponse.setAuthResult(BompAppParamConstant.FLAG_N);
        if (acctRealNameAuthRequest.getAcctName().equals(coreAcctInfoQueryResponse.getCustomerName())) {
            acctRealNameAuthResponse.setAuthResult(BompAppParamConstant.FLAG_Y);
            //查询人行行号
            SysParamService sysParamService = new SysParamServiceImpl();
            SysParam sysParam = sysParamService.getSysParamInfo(instId, BompAppParamConstant.MCHNT_PARAM_TYPE, BompAppParamConstant.INST_BANK_CODE);
            if (null != sysParam) {
                acctRealNameAuthResponse.setOpenBankNo(sysParam.getParamValue());
                acctRealNameAuthResponse.setOpenBankName(sysParam.getParamDesc());
            }
        }

        if ("SA".equals(coreAcctInfoQueryResponse.getAcctGroup())) {
            acctRealNameAuthResponse.setAcctType(SettleAcctTypeEnum.SELFT_PASSBOOK.getAcctType());
        } else if ("CR".equals(coreAcctInfoQueryResponse.getAcctGroup())) {
            //银行卡
            if ("01".equals(coreAcctInfoQueryResponse.getAcctType())) {
                //本行借机卡
                acctRealNameAuthResponse.setAcctType(SettleAcctTypeEnum.SELF_DEBIT.getAcctType());
            } else if ("02".equals(coreAcctInfoQueryResponse.getAcctType())) {
                //本行贷记卡
                acctRealNameAuthResponse.setAcctType(SettleAcctTypeEnum.SELF_CREDIT.getAcctType());
            }
        } else if ("GL".equals(coreAcctInfoQueryResponse.getAcctGroup())) {
            acctRealNameAuthResponse.setAcctType(SettleAcctTypeEnum.SELF_INTERNAL.getAcctType());
        }


        if (!acctRealNameAuthResponse.getAcctType().equals(acctRealNameAuthRequest.getSettleAcctType())) {
            rglog.info("传入结算账户类型与验证结算账户类型-失败，传入:<{}>,结果:<{}>", acctRealNameAuthRequest.getSettleAcctType(), acctRealNameAuthResponse.getAcctType());
            acctRealNameAuthResponse.setRespCode(RespCodeEnum.SETTLE_ACCT_TYPE_IS_NOT_MATCH.getRespCode());
            acctRealNameAuthResponse.setRespDesc(RespCodeEnum.SETTLE_ACCT_TYPE_IS_NOT_MATCH.getRespDesc() + SettleAcctTypeEnum.getAcctDescByacctType(acctRealNameAuthResponse.getAcctType()));
            acctRealNameAuthResponse.setAuthResult(BompAppParamConstant.FLAG_N);
            bizResponse.setRspSysId(AppParamConstant.SYS_ID);
            bizResponse.setRespCode(acctRealNameAuthResponse.getRespCode());
            bizResponse.setRespDesc(acctRealNameAuthResponse.getRespDesc());
            bizResponse.setResult(acctRealNameAuthResponse);
            return bizResponse;
        }


        /* 组装返回信息 */
        acctRealNameAuthResponse.setAcctStatus(result.getResult().getAcctStatus());
        bizResponse.setRespCode(RespCodeEnum.TRANS_SUCCESS.getRespCode());
        bizResponse.setRespDesc(RespCodeEnum.TRANS_SUCCESS.getRespDesc());
        bizResponse.setRspSysId(AppParamConstant.SYS_ID);
        bizResponse.setResult(acctRealNameAuthResponse);
        return bizResponse;
    }

    /**
     * 调用ESB平台
     *
     * @param acctRealNameAuthRequest 请求
     * @return 账户信息
     */
    private Result<BankAcctInfoQueryResponse> invokeEsbToGetCoreAcctInfoQueryResponse(AcctRealNameAuthRequest acctRealNameAuthRequest) throws Exception {
        ChannelCallCfg coreAcctInfoQuerychannelCallCfg = txnInfo.getChannelCallCfgList().get(0);
        BankAcctInfoQueryRequest coreAcctInfoQueryRequest = new BankAcctInfoQueryRequest();
        Header queryHeader = new Header();
        BeanUtil.beanCopy(acctRealNameAuthRequest.getHeader(), queryHeader);
        queryHeader.setInstId(acctRealNameAuthRequest.getHeader().getInstId());
        queryHeader.setChanlId(ChannelEnum.BOMP.getChannelType());
        queryHeader.setSrcSysId(AppParamConstant.SYS_ID);
        queryHeader.setTxnNum(coreAcctInfoQuerychannelCallCfg.getCallChannelTxn());
        queryHeader.setTransDate(DateUtil.getCurrentDate());
        queryHeader.setTransTime(DateUtil.getCurrentTime());
        queryHeader.setTraceNo(GlobalEsbUtil.generateEsbSeqeuenceNumber(acctRealNameAuthRequest.getHeader().getInstId()));
        coreAcctInfoQueryRequest.setAcctNo(acctRealNameAuthRequest.getAcctNo());
        coreAcctInfoQueryRequest.setHeader(queryHeader);
        DubboService dubboService = new DubboServiceImpl();
        return (Result<BankAcctInfoQueryResponse>) dubboService.callDubboService(DubboMethodConstant.DUBBO_BANK_SUP_SERVICE, "bankAcctInfoQuery", coreAcctInfoQueryRequest);
    }

    /**
     * 账户四要素校验
     *
     * @param acctRealNameAuthRequest 请求
     * @param sysSeqNum               系统流水号
     * @param bankSupService          esb业务支撑服务
     */
    private void invokeEsbToVerifyFourEle(AcctRealNameAuthRequest acctRealNameAuthRequest, String sysSeqNum, BankSupService bankSupService) throws Exception {
        ChannelCallCfg bankFourEleVerifychannelCallCfg = txnInfo.getChannelCallCfgList().get(0);
        BankFourElementVerifyRequest bankFourEleVerifyRequest = new BankFourElementVerifyRequest();
        Header verifyHeader = new Header();
        BeanUtil.beanCopy(acctRealNameAuthRequest.getHeader(), verifyHeader);
        verifyHeader.setChanlId(ChannelEnum.BOMP.getChannelType());
        verifyHeader.setSrcSysId(AppParamConstant.SYS_ID);
        verifyHeader.setTxnNum(bankFourEleVerifychannelCallCfg.getCallChannelTxn());
        verifyHeader.setTraceNo(GlobalEsbUtil.generateEsbSeqeuenceNumber(acctRealNameAuthRequest.getHeader().getInstId()));
        bankFourEleVerifyRequest.setHeader(verifyHeader);
        bankFourEleVerifyRequest.setAcctNo(acctRealNameAuthRequest.getAcctNo());
        bankFourEleVerifyRequest.setCustomerName(acctRealNameAuthRequest.getAcctName());
        bankFourEleVerifyRequest.setCertNo(acctRealNameAuthRequest.getCertNo());
        bankFourEleVerifyRequest.setCertType(acctRealNameAuthRequest.getCertType());
        bankFourEleVerifyRequest.setMobileNo(acctRealNameAuthRequest.getPhoneNo());

        Result<BankFourElementVerifyResponse> bankFourElementVerifyResponseResult = bankSupService.bankFourElementVerify(bankFourEleVerifyRequest);
        BankFourElementVerifyResponse bankFourEleVerifyResponse = bankFourElementVerifyResponseResult.getResult();
        if (!bankFourElementVerifyResponseResult.isSuccess() || !DubboMethodConstant.DUBBO_SUCCESS.equals(bankFourEleVerifyResponse.getRespCode())) {
            rglog.error("账户实名认证服务失败！调用ESB通道的进行四要素校验bankFourEleVerifyResponse返回失败,errorCode:{},errorMsg:{}",
                    bankFourEleVerifyResponse.getRespCode(), bankFourEleVerifyResponse.getRespDesc());
            throw new BizException(RespCodeEnum.CALL_BIZ_SERVICE_ERROR.getRespCode(), RespCodeEnum.CALL_BIZ_SERVICE_ERROR.getRespDesc());
        }

    }

    /**
     * 校验是否为本行卡
     *
     * @param acctRealNameAuthRequest 请求
     * @param instId                  机构号
     * @param sysSeqNum               系统流水号
     * @throws Exception 异常
     */
    private void verifyCardBinInfo(AcctRealNameAuthRequest acctRealNameAuthRequest, String instId, String sysSeqNum) throws Exception {
        /* 校验是否为本行卡 */
        BinInfoService binInfoService = new BinInfoServiceImpl();
        BinInfo binInfo = binInfoService.getCardBinInfo(acctRealNameAuthRequest.getAcctNo());

        SysParamService sysParamService = new SysParamServiceImpl();
        /* 银联码，获取法人行在银联的机构号 */
        SysParam unionPayCode = sysParamService.getSysParamInfo(instId, BompAppParamConstant.MCHNT_PARAM_TYPE, BompAppParamConstant.CUPS_INSR_ID);
        if (null == unionPayCode) {
            rglog.error("账户实名认证服务失败！获取法人行在银联的机构号失败！instId:{}，sysSeqNum:{}", instId, sysSeqNum);
            throw new BizException(RespCodeEnum.MCHNT_INFO_NOT_FOUND.getRespCode(), RespCodeEnum.MCHNT_INFO_NOT_FOUND.getRespDesc());
        }

        if (!binInfo.getIssuerCode().substring(0, 4).equals(unionPayCode.getParamValue().substring(0, 4))) {
            rglog.error("账户实名认证服务失败！只支持本行卡进行实名认证！sysSeqNum:{},发卡机构:{}，收单机构:{}", sysSeqNum, binInfo.getIssuerCode(), unionPayCode.getParamValue());
            throw new BizException(RespCodeEnum.NOT_SUPPORT_ORT_TYPE.getRespCode(), RespCodeEnum.NOT_SUPPORT_ORT_TYPE.getRespDesc());
        }
    }

    @Override
    protected void bizAfterCust(Object response) throws Exception {
        BizResponse bizResponse = (BizResponse) response;
        AcctRealNameAuthResponse acctRealNameAuthResponse = (AcctRealNameAuthResponse) bizResponse.getResult();
        ConvertUtil.convertInput(acctRealNameAuthResponse);
    }
}
